"""
Copyright © 2021 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-ws2812-research
"""
import framebuf
import math
from machine import I2C, Pin, Timer
from drivers.ssd1306 import SSD1306_I2C

DATA_DICT = {
	# fontface: JetBrains Mono ExtraBold, width: 20
	'0': memoryview(b'\x00\xe0\xe0p00p\xe0\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x7f\x7f\xe0\xcf\xc6\xe0\x7f?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'1': memoryview(b'\x00\xc0\xe0p\xf0\xf0\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc0\xc0\xc0\xff\xff\xff\xc0\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'2': memoryview(b'\x00\xe0\xe0p00\xf0\xe0\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\xf0\xf8\xdc\xdc\xcf\xc7\xc1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'3': memoryview(b'\x00000\xb0\xf0\xf0p\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00``\xe7\xc7\xc6\xfe~<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'4': memoryview(b'\x00\x00\x00\x80\xe0\xf00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>?710\xfe\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'5': memoryview(b'\x00\xf0\xf0000000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00gg\xe6\xc3\xc3\xe7~<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'6': memoryview(b'\x00\x00\x80\xc0\xf0p\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00~\x7f\xe7\xc7\xc6\xee~<\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'7': memoryview(b'\x00\xf0\xf0000\xf0\xf0p\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xe0\xfc?\x0f\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'8': memoryview(b'\x00\xe0\xf0p00\xf0\xe0\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00y\xff\xe7\xc6\xc6\xef\x7f8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	'9': memoryview(b'\x00\xe0\xe0p00p\xe0\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\x8f\x8e\xect>\x0f\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'),
	':': memoryview(b'\x00\x00\x00\x00\x80\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00A\xe3\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
}

class VerticalScrollTest(object):
	'''字符垂直滚动测试单元'''
	def __init__(self, oled):
		self.__char_count = 5
		self.__timer = Timer(0)
		self.__oled = oled
		self.oled_width = self.__oled.width
		self.oled_height = self.__oled.height
		self.font_width = self.font_height = 20
		self.__pos_x = (self.oled_width - self.font_width * self.__char_count) // 2
		self.__pos_y = (self.oled_height - self.font_height) // 2

		# 滚动字符缓冲区，映射尺寸：1 个字符宽，2 个字符高
		self.__scrolling_framebuffers = [framebuf.FrameBuffer(
			bytearray(math.ceil(self.font_height / 8) * self.font_width * 2),
			self.font_width,
			self.font_height * 2,
			framebuf.MONO_VLSB
		) for _ in range(self.__char_count)]

		self.__chars_framebuffer = {
			char: framebuf.FrameBuffer(
				bytearray(DATA_DICT.get(char)),
				self.font_width,
				self.font_height,
				framebuf.MONO_VLSB
			) for char in '0123456789:'
		}

	def start(self, minute=59, second=56):
		self.minute = minute
		self.second = second
		self.__minute_changed = False # 调整分钟数滚动顺序

		self.__show_time(f'{self.__zfill(self.minute)}:{self.__zfill(self.second)}')

		self.__timer.init(
			mode=Timer.PERIODIC,
			period=1000,
			callback=self.__scroll_timer_cb
		)

	def __scroll_timer_cb(self, _):
		second_char_before = self.__zfill(self.second)
		minute_char_before = self.__zfill(self.minute)
		self.second += 1

		if self.second >= 60:
			self.second = 0
			self.minute += 1
			self.__minute_changed = True

		second_char = self.__zfill(self.second)
		self.__scroll_char(4, second_char[1], second_char_before[1])

		if second_char[1] == '0':
			self.__scroll_char(3, second_char[0], second_char_before[0])

		if self.__minute_changed:
			if self.minute >= 60:
				self.minute = 0

			minute_char = self.__zfill(self.minute)
			self.__scroll_char(1, minute_char[1], minute_char_before[1])

			if minute_char[1] == '0':
				self.__scroll_char(0, minute_char[0], minute_char_before[0])

			self.__minute_changed = False

	def __scroll_char(self, pos, char, char_before):
		self.__scrolling_framebuffers[pos].blit(self.__chars_framebuffer.get(char_before), 0, 0)
		self.__scrolling_framebuffers[pos].blit(self.__chars_framebuffer.get(char), 0, self.font_height)

		scroll_count = 0
		scroll_step = 4

		for _ in range(self.font_height // scroll_step):
			self.__scrolling_framebuffers[pos].scroll(0, -1 * scroll_step)
			self.__oled.blit(self.__scrolling_framebuffers[pos], self.__pos_x + pos * self.font_width, self.__pos_y)
			self.__oled.show()
			scroll_count += scroll_step

		# 修正滚动错位
		if self.font_height > scroll_count:
			self.__scrolling_framebuffers[pos].scroll(0, -1 * (self.font_height - scroll_count))
			self.__oled.blit(self.__scrolling_framebuffers[pos], self.__pos_x + pos * self.font_width, self.__pos_y)
			self.__oled.show()
		elif self.font_height < scroll_count:
			self.__scrolling_framebuffers[pos].scroll(0, scroll_count - self.font_height)
			self.__oled.blit(self.__scrolling_framebuffers[pos], self.__pos_x + pos * self.font_width, self.__pos_y)
			self.__oled.show()

	def __show_time(self, chars):
		for index, char in enumerate(chars):
			self.__oled.blit(self.__chars_framebuffer.get(char), self.__pos_x + index * self.font_width, self.__pos_y)

		self.__oled.show()

	def __zfill(self, value):
		'''将时分秒填充为 2 位'''
		value = str(value)
		return '0' + value if len(value) == 1 else value


if __name__ == '__main__':
	i2c = I2C(0, scl=Pin(18), sda=Pin(19))
	slave_list = i2c.scan()

	if slave_list:
		oled = SSD1306_I2C(128, 64, i2c)
		test = VerticalScrollTest(oled)
		test.start()
